unix系统之套接字通信

您所在的位置:网站首页 recv 返回值 unix系统之套接字通信

unix系统之套接字通信

2023-04-10 15:24| 来源: 网络整理| 查看: 265

概述创建套接字domaintypeprotocol绑定网络域sockaddr监听套接字接受请求连接网络域发送消息接收消息关闭套接字的连接例子服务端客户端其他

概述

socket(套接字)通信主要用于运行在不同服务器上的进程之间通信(服务器通过网络相连),也可以用于在同一服务器上的进程之间通信。套接字就相当于端与端之间的独立的门,通信就通过这个门来进行。

创建套接字

创建成功返回一个套接字描述符,基本上可以把它看成是一个文件描述符,很多文件描述符的api,对套接字描述符也是适用的。

#include int socket(int domain, int type, int protocol);

domain

决定了通信的性质,这些性质包括地址格式等,一般有以下值:

AF_INET:IPv4 因特网域。AF_INET6:IPv6 因特网域。AF_UNIX: UNIX 域。大多系统还定义了AF_LOCAL域,它是AF_UNIX的别名。AF_UNSPEC: 未指定,这是一个可以表达任何域的通配符。

type

参数的类型,一般有以下:

SOCK_DGRAM:固定长度,无连接,不可靠的消息。SOCK_RAW: IP 协议的数据报接口。(在 POSIX.1 中是可选的)SOCK_SEQPACKET: 固定长度,顺序式,面向连接的,可靠的消息。

SOCK_STREAM: 顺序式,面向连接的,双向的,可靠的字节流。

protocol

通常是0,表示为给定的域和套接字类型的组合选择默认协议。当一对域和套接字类型支持多个协议时,可用protocol参数选择一个特定协议。AF_INET通信域和SOCK_STREAM套接字类型的默认协议是TCP。AF_INET通信域和SOCK_DGRAM套接字类型的默认协议是UDP。以下是protocol参数的可选值:

IPPROTO_IP :IPv4网络协议

IPPROTO_IPV6 :IPv6网络协议IPPROTO_ICMP :因特网控制报文协议IPPROTO_RAW: 原始数据包协议IPPROTO_TCP: 传输控制协议IPPROTO_UDP: 用户数据报协议

绑定网络域

当通过socket函数获得套接字描述符后,对于服务端来讲,首先就是和一个具体的网络地址绑定,这个套接字一般称为监听套接字,其函数为:

#include int bind(int sockfd, const struct sockaddr *addr, socklen_t len); sockfd:套接字描述符addr:绑定的网络域len:addr的长度

sockaddr

一个const struct sockaddr *指针, 绑定套接字的网络域,不同的网络域具有不同的地址格式,sockaddr 是地址的通用结构体:

struct sockaddr { sa_family_t sa_family;/* address family */ char sa_data[];/* variable-length address */ . . . };

这个地址结构根据地址创建socket时的地址协议族的不同而不同,如ipv4对应的是:

struct sockaddr_in { sa_family_t sin_family; /* address family: AF_INET */ in_port_t sin_port; /* port in network byte order */ struct in_addr sin_addr; /* internet address */};/* Internet address. */struct in_addr { uint32_t s_addr; /* address in network byte order */};

如ipv6对应的是:

struct sockaddr_in6 { sa_family_t sin6_family; /* AF_INET6 */ in_port_t sin6_port; /* port number */ uint32_t sin6_flowinfo; /* IPv6 flow information */ struct in6_addr sin6_addr; /* IPv6 address */ uint32_t sin6_scope_id; /* Scope ID (new in 2.4) */ };struct in6_addr { unsigned char s6_addr[16]; /* IPv6 address */ };

如unix对应的是:

#define UNIX_PATH_MAX 108struct sockaddr_un { sa_family_t sun_family; /* AF_UNIX */ char sun_path[UNIX_PATH_MAX]; /* pathname */ };

监听套接字

服务端针对面向连接的套接字进行监听,保证连接的有效性。服务端的监听函数如下:

int listen(int sockfd, int backlog);

backlog 参数表示能够排队最大连接请求数量,但实际最大的值的上限由系统决定,毕竟不可能设置一个超越系统配置的数量。很明显,这个参数表明了内核需要维护一个存储与客户端连接关系的队列。

接受请求

服务端通过监听函数可以发现那些发起连接请求的客户端,而accept函数是去为这些客户端建立起真正的连接关系,函数如下:

int accept(int sockfd, struct sockaddr *restrict addr,socklen_t *restrict len);

accept默认会阻塞进程,直到有一个客户连接建立后返回,若函数成功返回,返回值是一个由内核自动生成的全新的套接字,代表与客户端的连接。也就是说,服务端每有新的客户端连接都会新建一个套接字。

连接网络域

当通过socket函数获得套接字描述符后,对于客户端来讲,就是可以与服务端具体的网络域进行连接了,函数如下:

int connect(int sockfd, const struct sockaddr *addr, socklen_t len);

发送消息ssize_t send(int sockfd, const void *buf, size_t nbytes, int flags)ssize_t sendto(int sockfd, const void *buf, size t nbytes, int flags, const struct sockaddr *destaddr, socklen t destlen);ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);

flag: 0 阻塞、1 不阻塞

接收消息ssize_t recv(int sockfd, void *buf, size t nbytes, int flags):ssize_t recvfrom(int sockfd, void *restrict buf, size t len, int flags, struct sockaddr *restrict addr,socklen t *restrict addrlen);ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

flag: 0 阻塞、1 不阻塞

关闭套接字的连接int shutdown (int sockfd, int how);

how是指关闭的方式:

SHUT_RD: 关闭读。SHUT_WR: 关闭写。SHUT_RDWR: 关闭读写。

例子

因为基于SOCK_DGRAM类型的套接字比较简单,所以直接搞个SOCK_STREAM的一步到位。服务端建立一个面向连接的套接字,去接收多个客户端的消息。客户端输入”end”结束连接。

服务端#include #include #include #include #include #include #include int main(int argc, char *argv[]){ struct sockaddr_in clientaddr, serveraddr; int sockfd; int connectSockfd; int addrlen; pid_t pid; // 创建socket文件描述符用于处理监听 if ((sockfd = socket(AF_INET, SOCK_STREAM, 0))


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3